Wer einen genauen Frequenzzähler zur Verfügung hat, kann die Gangabweichung unter Kontrolle bringen:
Aber wie erreicht man eine Genauigkeit von 10-6 bei lauter
8-bit-Teilern?
Irgendwelche Fummeleien mit umschaltenden Teilern sehen nicht gerade
elegant aus...
Die Lösung ist ein genügend breiter Überlauf-Zähler. Wie funktioniert das?
... dec r18 ;r18 sei der ISR-Teiler brne ende ldi r18,32 call SekundeVergangen ende: ...Damit wird ein 5-Bit-Zähler simuliert.
... ldi r16,8 add r18,r16 ;r18 sei der ISR-Akkumulator brcc ende call SekundeVergangen ende: ...
Tint = 1024 * 256 / fosz, fosz = 8000000 HzErwischt! Mit Zeiten rechnen ist einfacher!
Tint = 1024 * 256 * Tosz, Tosz = 125 nsDie Zeit beträgt in diesem Falle:
0,032768 sAlso eine Zahl, die kleiner als Eins (eine Sekunde) ist, und das ist gut so!
Dazu ermitteln wir einen (endlichen) Bruch, in dessen Nenner die computerfreundliche Zahl 232 steht, wir erweitern also um 232:
Tint = 1024 * 256 * Tosz * 232 / 232Und fortan nehmen wir davon nur den (gerundeten) Zähler. Der ist eine riesige Ganzzahl und beträgt hier:
140737488 - hexadezimal 0x08637BD0Noch einmal: Das ist der Zähler für den Binärbruch, in dessen Nenner 232 steht. Damit erreichen wir eine Auflösung von 1/140737488, also unter 10-8. Eine Uhr hätte damit eine Gangabweichung von 1 Sekunde in 4 Jahren. Das ist mit einem nicht temperaturstabilisierten Quarz, noch dazu am simplen Mikrocontroller, absolut illusorisch. 3 Bytes reichen auch: 1/(0x08637B+1) (Rundung) ergibt 1,8*10-6, 1 Sekunde in 6 Tagen.
Und was macht man nun damit?
Diese Konstante wird bei jedem Interrupt auf einen 4-Byte-Akkumulator addiert;
bei jedem Überlauf ist eine Sekunde vergangen!
In Atmel-Worten:
Exakt gleich lange Sekunden können nur mit einem gezogenen Quarz
erreicht werden.
Andererseits darf SekundeVergangen auch die Interrupts freigeben;
darf dann allerdings nicht mehr als eine knappe Sekunde verbrauchen,
alles bei voller sonstiger Interruptlast.
Ein Uhrenvergleich mit einer Funkuhr ist ein sehr langwieriges Unterfangen
und sollte nur im Notfall nach guter Vorbereitung erfolgen.
Als Messzeit sollte man 24 Stunden einplanen.
Die Quarzfrequenz darf keinesfalls direkt am Quarz gemessen werden,
weil die Tastspitze mit ihrer (kapazitiven) Last unweigerlich den
Quarz wegzieht.
Schreiben Sie in Ihre ISR Kode hinein, das ein Ausgabepin hin- und her
schaltet (toggelt, halbe Frequenz beachten!) oder pulst.
Oder aber, geben Sie im Sekundentakt einen Puls aus.
Hierbei ist der Jitter ist für das Kalibrieren katastrophal, deshalb
benutzt man zunächst einen »geraden« Wert für die Konstante, bspw. 0x08000000.
Die Quarz-Periodendauer ergibt sich dann einfach zu:
Für eine Kennlinie brauchen Sie einen Gefrierschrank und einen Ofen,
um für jede Temperatur (bspw. alle 5 °C) die Oszillatorperiodendauer zu messen.
Dieser 4-Byte-Akkumulator beinhaltet die »Nachkomma-
.dseg
VierByteAkku: .byte 4
.cseg
Timer0ISR:
push r16
in r16,sreg
push r16
push xl ;xh sei stillschweigend stets Null
push r4
ldi xl,VierByteAkku
ld r4,x
ldi r16,$D0 ;letztes Byte
add r4,r16
st x+,r4
ld r4,x ; das schreit
ldi r16,$7B ; nach
adc r4,r16 ; einem
st x+,r4 ; Makro
ld r4,x
ldi r16,$63
adc r4,r16
st x+,r4
ld r4,x
ldi r16,$08 ;erstes Byte
adc r4,r16
st x+,r4
pop r4
pop xl
jnc ende
call SekundeVergangen
ende: pop r16
out sreg,r16
pop r16
reti
Und das ist alles, was von der grauen Theorie übrig bleibt!
Jitter-Betrachtungen
Der Sekunden-Tick tritt alle 31..32 Zeitgeber-Interrupts auf.
Die Programm-Reentranz-Betrachtungen
Das Unterprogramm SekundeVergangen darf keinesfalls länger als
knapp zwei Interruptperioden Zeit verbrauchen,
denn verschluckte Interrupts führen zur falschen Uhrzeit!
Andernfalls kommt es zur Reentranz (= ungewollte Rekursion).
Dagegen helfen selbstgebastelte Semaphoren (siehe anderes Kapitel).
Kalibriervorgang
Sie benötigen dazu ein genügend genaues Frequenz/Periodendauermessgerät.
Lassen Sie es nach Vorschrift/Bedienungsanleitung warmlaufen.
Tosz = Tgemessen
/ Vorteiler / 256 ( / 32 für Sekundentakt)
Notieren Sie dabei die Temperatur der Schaltung.